# Copyright (C) 2004, 2005  Fletcher T. Penney <fletcher@freeshell.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
#    Free Software Foundation, Inc.
#    59 Temple Place, Suite 330
#    Boston, MA 02111-1307 USA


$Action{edit} = \&CustomDoEdit;

sub CustomDoEdit {
    my ($id, $newText, $preview) = @_;
    ValidIdOrDie($id);
    my $upload = GetParam('upload', undef);
    if (!UserCanEdit($id, 1)) {
        my $rule = UserIsBanned();
        if ($rule) {
            ReportError(T('Edit Denied'), '403 FORBIDDEN', undef,
                $q->p(T('Editing not allowed: user, ip, or network is blocked.')),
                $q->p(T('Contact the wiki administrator for more information.')),
                $q->p(Ts('The rule %s matched for you.', $rule) . ' ' . Ts('See %s for more information.', GetPageLink($BannedHosts))));
        } else {
                ReportError(T('Edit Denied'), '403 FORBIDDEN', undef,
                $q->p(Ts('Editing not allowed: %s is read-only.', NormalToFree($id))));
        }
    } elsif ($upload and not $UploadAllowed and not UserIsAdmin()) {
        ReportError(T('Only administrators can upload files.'), '403 FORBIDDEN');
    }
    OpenPage($id);
    my ($text, $revision) = GetTextRevision(GetParam('revision', ''), 1); # maybe revision reset!
    my $oldText = $preview ? $newText : $text;
    my $isFile = TextIsFile($oldText);
    $upload = $isFile if not defined $upload;
    if ($upload and not $UploadAllowed and not UserIsAdmin()) {
        ReportError(T('Only administrators can upload files.'), '403 FORBIDDEN');
    }
    if ($upload) { # shortcut lots of code
        $revision = '';
        $preview = 0;
    } elsif ($isFile and not $upload) {
        $oldText = '';
    }
    my $header;
    if ($revision and not $upload) {
        $header = Ts('Editing revision %s of', $revision) . ' ' . $id;
    } else {
        $header = Ts('Editing %s', $id);
    }

# By not declaring a doctype, browsers turn on quirk mode, which in
# turn allows for proper handling of 100% height on blocks. 
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
print GetHttpHeader('text/html', $nocache, $status);
print <<EOF; # Print everything up until EOF
<html>
<head>
<meta name="robots" content="NOINDEX,NOFOLLOW" />
<link rel="stylesheet" type="text/css" href="/css/edit.css" />

EOF
if ($preview and not $upload) {
    print '<style type="text/css"> div#eview { display: none; } </style>';
} else {
    print '<style type="text/css"> div#pview { display: none; } </style>';
}
    print "<script type=\"text/Javascript\" src=\"/js/csshide.js\"></script>";
    print "<title>$SiteName : Editing $id</title>";
    print "</head>";
    print '<body>'; 
     
    print GetFormStart(undef, undef, $upload ? 'edit upload' : 'edit text'); # protected by questionasker
    
    print $q->start_div({-id=>'eview'});
    print $q->p({-class=>'hidden'},GetHiddenValue("title", $id));
    print $q->p({-class=>'hidden'},$revision ? GetHiddenValue('revision', $revision) : '');
    print $q->p({-class=>'hidden'},GetHiddenValue('oldtime', $Page{ts}));
    
    print '<table border="0" width="100%" class="outertable">';
    print ' <tr>';
    print '  <td>';
    print '   <table border="0" width="100%">';
    print '    <tr class="header">';
    print '     <td valign="middle"><h1>Editing '. $id . '</h1></td>';
    print '     <td valign="middle"><p>';
    if ($revision) {
        print '<strong>Editing old revision ' . $revision . ', <em>Saving will overwrite the original!!!</em></strong>';
    }
    print '</p></td>';
    print '     <td valign="middle" align="right"><p>Do not show in RecentChanges ' . $q->checkbox(-name=>"recent_edit", -checked=>1, -label=>T("")) . '</p></td>';
    print '    </tr>';
    print '   </table>';
    print '  </td>';
    print ' </tr>';
    print ' <tr>';
    print '  <td colspan="3" valign="top" id="textcell">';
    #print $upload ? GetUpload() : GetTextArea('text', $oldText);
    if ($upload) { 
        print GetUpload();
    } else {
        print $q->textarea({-id=>'workarea', -name=>'text', -default=>$oldText, -override=>1, -rows=>'10', -cols=>'78'});
    }
    print '  </td>';
    print ' </tr>';
    print ' <tr class="footer">';
    print '  <td>';
    print '   <table border="0" width="100%">';
    print '    <tr>';
    print '     <td valign="middle"><p>Changed ';
    my $summary = "I am an idiot, I refuse to document my changes...";
    print $q->textfield(-id=>'summary', -name=>'summary', -default=>$summary, -override=>1, -onFocus=>'clearDefault(this)');
    print '     </p></td>';
    print '     <td valign="middle" id="name"><p>Name ';
    my $username = GetParam('username', '');
    print $q->textfield(-name=>'username', -id=>'username', -default=>$username, -override=>1, -size=>13, -maxlength=>50);
    print '</p></td>';
    print '     <td valign="middle" id="boxes"><p>';
   
    print $q->submit(-name=>'Save', -accesskey=>T('s'), -value=>T('Save'));
    print $upload ? '' :  ' ' . $q->submit(-name=>'Preview', -accesskey=>T('p'), -value=>T('Preview'));
    
    if ($upload) {
        print ScriptLink('action=edit;upload=0;id=' . UrlEncode($id), T('Make Text'));
    } elsif ($UploadAllowed or UserIsAdmin()) {
        print ScriptLink('action=edit;upload=1;id=' . UrlEncode($id), T('Upload'));
    }

    print '</p></td>';
    print '    </tr>';
    print '   </table>';
    print '  </td>';
    print ' </tr>';
    print '</table>';
    print $q->end_div(); 
    print $q->endform();

    if ($preview and not $upload) {
        print $q->start_div({-id=>'pview'});
        print '<table border="0" width="100%" class="outertable">';
        print ' <tr>';
        print '  <td>';
        print '   <table border="0" width="100%">';
        print '    <tr class="header">';
        print '     <td valign="middle"><h1>This is a preview of '. $id . '</h1></td>';
        print '    </tr>';
        print '   </table>';
        print '  </td>';
        print ' </tr>';
        print ' <tr>';
        print '  <td colspan="3" valign="top" id="textcell">';
        print '   <div id="prearea">';
        PrintWikiToHTML($oldText); # no caching, current revision, unlocked
        print '   </div>';
        print '  </td>';
        print ' </tr>';
        print ' <tr class="footer">';
        print '  <td>';
        print '   <table border="0" width="100%">';
        print '    <tr>';
        print '     <td align="right">';
        print        $q->p($q->a({-href=>'javascript:toggleOn(\'eview\'); javascript:toggleOff(\'pview\');'},'Go Back and Edit'));
        print '     </td>';
        print '    </tr>';
        print '   </table>';
        print '  </td>';
        print ' </tr>';
        print '</table>';
        print $q->end_div();
    }

    print "</body></html>";
}


*OldDoPost = *DoPost;
*DoPost = *CustomDoPost;

sub CustomDoPost {
  my $id = FreeToNormal(shift);
  ValidIdOrDie($id);
  ReportError(Ts('Editing not allowed for %s.', $id), '403 FORBIDDEN') unless UserCanEdit($id, 1);
  my $filename = GetParam('file', undef);
  if ($filename and not $UploadAllowed and not UserIsAdmin()) {
    ReportError(T('Only administrators can upload files.'), '403 FORBIDDEN');
  }
  # Lock before getting old page to prevent races
  RequestLockOrError(); # fatal
  OpenPage($id);
  my $old = $Page{text};
  $_ = UnquoteHtml(GetParam('text', undef));
  foreach my $macro (@MyMacros) { &$macro; }
  my $string = $_;
  my $comment = UnquoteHtml(GetParam('aftertext', undef));
  # Upload file
  if ($filename) {
    require MIME::Base64;
    my $file = $q->upload('file');
    if (not $file and $q->cgi_error) {
      ReportError(Ts('Transfer Error: %s', $q->cgi_error), '500 INTERNAL SERVER ERROR');
    }
    ReportError(T('Browser reports no file info.'), '500 INTERNAL SERVER ERROR')
      unless $q->uploadInfo($filename);
    my $type = $q->uploadInfo($filename)->{'Content-Type'};
    ReportError(T('Browser reports no file type.'), '415 UNSUPPORTED MEDIA TYPE') unless $type;
    my %allowed = map {$_ => 1} @UploadTypes;
    ReportError(Ts('Files of type %s are not allowed.', $type), '415 UNSUPPORTED MEDIA TYPE')
      if @UploadTypes and not $allowed{$type};
    local $/ = undef;   # Read complete files
    eval { $_ = MIME::Base64::encode(<$file>) };
    $string = '#FILE ' . $type . "\n" . $_;
  } else {
    $string = AddComment($old, $comment) if $comment;
    $string = substr($string, length($DeletedPage)) # undelete pages when adding a comment
      if $comment and substr($string, 0, length($DeletedPage)) eq $DeletedPage; # no regexp!
    # Massage the string
    $string =~ s/\r//g;
    $string .= "\n"  if ($string !~ /\n$/);
    $string =~ s/$FS//g;
  }
  # Banned Content
  my $summary = GetSummary();
  if (not UserIsEditor()) {
    my $rule = BannedContent($string) || BannedContent($summary);
    ReportError(T('Edit Denied'), '403 FORBIDDEN', undef,
                $q->p(T('The page contains banned text.')),
                $q->p(T('Contact the wiki administrator for more information.')),
                $q->p($rule . ' ' . Ts('See %s for more information.', GetPageLink($BannedContent))))
      if $rule;
  }
  # rebrowse if no changes
  my $oldrev = $Page{revision};
  if (GetParam('Preview', '')) { # Preview button was used
    ReleaseLock();
    if ($comment) {
      BrowsePage($id, 0, $comment);
    } else {

      CustomDoEdit($id, $string, 1);
    }
    return;
  } elsif ($old eq $string) {
    ReleaseLock(); # No changes -- just show the same page again
    return ReBrowsePage($id);
  } elsif ($oldrev == 0 and ($string eq $NewText or $string eq "\n")) {
    ReportError(T('No changes to be saved.'), '400 BAD REQUEST'); # don't fake page creation because of webdav
  }
  my $newAuthor = 0;
  if ($oldrev) { # the first author (no old revision) is not considered to be "new"
    # prefer usernames for potential new author detection
    $newAuthor = 1 if not $Page{username} or $Page{username} ne GetParam('username', '');
    $newAuthor = 1 if not $ENV{REMOTE_ADDR} or not $Page{ip} or $ENV{REMOTE_ADDR} ne $Page{ip};
  }
  my $oldtime = $Page{ts};
  my $myoldtime = GetParam('oldtime', ''); # maybe empty!
  # Handle raw edits with the meta info on the first line
  if (GetParam('raw', 0) == 2 and $string =~ /^([0-9]+).*\n((.*\n)*.*)/) {
    $myoldtime = $1;
    $string = $2;
  }
  my $generalwarning = 0;
  if ($newAuthor and $oldtime ne $myoldtime and not $comment) {
    if ($myoldtime) {
      my ($ancestor, $minor) = GetTextAtTime($myoldtime);
      if ($ancestor and $old ne $ancestor) {
        my $new = MergeRevisions($string, $ancestor, $old);
        if ($new) {
          $string = $new;
          if ($new =~ /^<<<<<<</m and $new =~ /^>>>>>>>/m) {
            SetParam('msg', Ts('This page was changed by somebody else %s.',
                               CalcTimeSince($Now - $Page{ts}))
                     . ' ' . T('The changes conflict.  Please check the page again.'));
          } # else no conflict
        } else { $generalwarning = 1; } # else merge revision didn't work
      } # else nobody changed the page in the mean time (same text)
    } else { $generalwarning = 1; } # no way to be sure since myoldtime is missing
  } # same author or nobody changed the page in the mean time (same timestamp)
  if ($generalwarning and ($Now - $Page{ts}) < 600) {
    SetParam('msg', Ts('This page was changed by somebody else %s.',
                       CalcTimeSince($Now - $Page{ts}))
             . ' ' . T('Please check whether you overwrote those changes.'));
  }
  Save($id, $string, $summary, (GetParam('recent_edit', '') eq 'on'), $filename);
  ReleaseLock();
  DeletePermanentAnchors();
  ReBrowsePage($id);
}
1;
